<?php

/**
 * uniBoard ACL Builder Class
 *
 * Light and fast forum solution for web 2.0-like communities.
 *
 * @package		uniBoard
 * @author		Rafał Pitoń
 * @license		http://www.gnu.org/licenses/gpl-3.0.html
 * @since		Version 0.1
 * 
 * ------------------------------------------------------------------------
 * 
 * $Date: 2010-09-20 21:23:27 +0000 (Mon, 20 Sep 2010) $
 * $Revision: 64 $
 * $Author: rafio.xudb@gmail.com $
 */

// ------------------------------------------------------------------------

class class_acl_builder{
	
	/**
	 * Main class pointer
	 *
	 * @var object
	 */
	
	private $appCore		= NULL;
	
	/**
	 * Permissions Cache
	 *
	 * @var array
	 */
	
	private $permissions	= array();
	
	/**
	 * Groups Cache
	 *
	 * @var array
	 */
	
	private $groups			= array();
	
	/**
	 * Masks Cache
	 *
	 * @var array
	 */
	
	private $masks			= array();
	
	/**
	 * User Masks
	 *
	 * @var array
	 */
	
	private $user_masks		= array();
	
	/**
	 * Forums Cache
	 *
	 * @var array
	 */
	
	private $forums			= array();
	
	/**
	 * Ready ACL
	 *
	 * @var array
	 */
	
	private $acl			= array();
	
	// ------------------------------------------------------------------------

	/**
	 * Initialise Action
	 *
	 * @param object $appCore
	 */
	
	function __construct( $appCore){
		
		// Store appCore pointer
		$this -> appCore = $appCore;
		
		// Load Permissions
		$this -> permissions = $appCore -> getPermissions();
		
		// Load Forums
		$this -> forums = $appCore -> getForums();
		
		// Load Groups Masks (no way we gonna load entire cache from DB)
		$this -> groups = class_cache::loadCache( 'groups_masks');
		
		// Cache Not Loaded?
		if ( class_cache::$load_error)
		{
			// Make Empty groups List
			$this -> groups = array();
			
			// Select Groups Masks
			$appCore -> db -> query( 'SELECT group_id, group_masks FROM ' . DB_PREFIX . 'user_groups');
			
			// Pass Result
			while ( $group_result = $appCore -> db -> fetch_array())
			{
				$this -> groups[$group_result[0]] = explode( ',', $group_result[1]);
			}
			
			// Save Cache
			class_cache::saveCache( 'groups_masks', $this -> groups);
			
			// Garbage out
			unset($group_result);
		}
		
		// Load Masks
		$this -> masks = class_cache::loadCache( 'permission_masks');
		
		// Cache Not Loaded?
		if ( class_cache::$load_error)
		{
			// Make Empty masks List
			$this -> masks = array();
			
			// Select Masks
			$appCore -> db -> query( 'SELECT mask_id, mask_permissions FROM ' . DB_PREFIX . 'permission_masks');
			
			// Pass Result
			while ( $mask_result = $appCore -> db -> fetch_array())
			{
				$this -> masks[$mask_result[0]] = (array) unserialize( $mask_result[1]);
			}
			
			// Save Cache
			class_cache::saveCache( 'permission_masks', $this -> masks);
			
			// Garbage out
			unset($mask_result);
		}
		
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Generates ACL
	 *
	 * @param array $groups
	 * @param array $masks
	 * @return array
	 */
	
	function makeACL( $groups, $masks){
		
		// Clear User Masks
		$this -> user_masks = array();
		
		// Reiterate Masks
		foreach ( $masks as $mask_id)
		{
			// Add Mask Id?
			if ( $mask_id > 0 && !in_array( $masks, $this -> user_masks))
			{
				$this -> user_masks[] = $mask_id;
			}
		}
		
		// Reiterate Groups
		foreach ( $groups as $group_id)
		{
			// Group has Masks?
			if ( isset( $this -> groups[$group_id]) && is_array( $this -> groups[$group_id]))
			{
				// Reiterate Group's Masks
				foreach ( $this -> groups[$group_id] as $mask_id)
				{
					// Add Mask Id?
					if ( $mask_id > 0 && !in_array( $masks, $this -> user_masks))
					{
						$this -> user_masks[] = $mask_id;
					}
				}
			}
		}
		
		// Reiterate Permissions
		foreach ( $this -> permissions as $perm_id => $perm_data)
		{
			// Force Perm?
			if ( $this -> appCore -> arrays_collide( $perm_data['permission_force'], $groups))
			{
				// Set Max Value
				switch ( $perm_data['permission_type'])
				{
					case 0:
						// Set Opposite to direction
						$this -> acl[$perm_id] = !$perm_data['permission_desc'];
					break;
					
					case 1:
						// Set Min or Max
						$this -> acl[$perm_id] = ($perm_data['permission_desc'] ? $perm_data['permission_extra']['MIN_VAL'] : $perm_data['permission_extra']['MAX_VAL']);
					break;
					
					case 2:
						// Set First or Max Item
						$this -> acl[$perm_id] = ($perm_data['permission_desc'] ? reset( array_keys( $perm_data['permission_extra'])) : end( array_keys( $perm_data['permission_extra'])));
					break;
				}
			}
			else if ( $this -> appCore -> arrays_collide( $perm_data['permission_forbid'], $groups))
			{
				// Set Min Value
				switch ( $perm_data['permission_type'])
				{
					case 0:
						// Set Direction
						$this -> acl[$perm_id] = $perm_data['permission_desc'];
					break;
					
					case 1:
						// Set Min or Max
						$this -> acl[$perm_id] = ($perm_data['permission_desc'] ? $perm_data['permission_extra']['MAX_VAL'] : $perm_data['permission_extra']['MIN_VAL']);
					break;
					
					case 2:
						// Set First or Max Item
						$this -> acl[$perm_id] = ($perm_data['permission_desc'] ? end( array_keys( $perm_data['permission_extra'])) : reset( array_keys( $perm_data['permission_extra'])));
					break;
				}
			}
			else
			{
				// First Mask?
				$first_mask = true;
				
				// Reiterate Masks
				foreach ( $this -> user_masks as $mask_id)
				{
					// Mask exsits?
					if ( isset( $this -> masks[$mask_id][$perm_id]))
					{
						// First Mask?
						if ( $first_mask)
						{
							// Set Mask's Value
							$this -> acl[$perm_id] = $this -> masks[$mask_id][$perm_id];
							
							// Next one is not first
							$first_mask = false;
						}
						else
						{
							// Our Perm overwrites current value under following conditions:
							// Current one is not locked zero
							// AND Our Value is BETTER according to perms direction
							if (!($perm_data['permission_zero_nulls'] && $this -> acl[$perm_id] == 0) && (($perm_data['permission_desc'] && $this -> acl[$perm_id] > $this -> masks[$mask_id][$perm_id]) || (!$perm_data['permission_desc'] && $this -> acl[$perm_id] < $this -> masks[$mask_id][$perm_id])))
							{
								// Set Mask's Value
								$this -> acl[$perm_id] = $this -> masks[$mask_id][$perm_id];
							}
						}
					}
				}
			}
		}
		
		// Set Empty Forums ACL
		$this -> acl['forum_show'] = array();
		$this -> acl['forum_read'] = array();
		$this -> acl['topics_start'] = array();
		$this -> acl['topics_reply'] = array();
		$this -> acl['files_upload'] = array();
		$this -> acl['files_download'] = array();
		
		// Reiterate our forums
		foreach ( $this -> forums as $forum_id => $forum_data)
		{
			// Reiterate Masks
			foreach ( $this -> user_masks as $mask_id)
			{
				// Mask exsits?
				if ( isset( $this -> masks[$mask_id]))
				{
					// Can we see forum?
					if ( $forum_data['forum_parent'] == 0 || in_array($forum_data['forum_parent'], $this -> acl['forum_read']))
					{
						// See Forum?
						if ( !in_array( $forum_id, $this -> acl['forum_show']) && in_array( $forum_id, $this -> masks[$mask_id]['forum_show']))
						{
							$this -> acl['forum_show'][] = $forum_id;
						}
						
						// Read Forum?
						if ( in_array( $forum_id, $this -> acl['forum_show']) && !in_array( $forum_id, $this -> acl['forum_read']) && in_array( $forum_id, $this -> masks[$mask_id]['forum_read']))
						{
							$this -> acl['forum_read'][] = $forum_id;
						}
					}
					
					// Start Topics
					if ( !in_array( $forum_id, $this -> acl['topics_start']) && in_array( $forum_id, $this -> masks[$mask_id]['topics_start']))
					{
						$this -> acl['topics_start'][] = $forum_id;
					}
					
					// Reply in Topics
					if ( !in_array( $forum_id, $this -> acl['topics_reply']) && in_array( $forum_id, $this -> masks[$mask_id]['topics_reply']))
					{
						$this -> acl['topics_reply'][] = $forum_id;
					}
					
					// Upload and download our attachments
					if ( !in_array( $forum_id, $this -> acl['files_upload']) && in_array( $forum_id, $this -> masks[$mask_id]['files_upload']))
					{
						$this -> acl['files_upload'][] = $forum_id;
					}
					
					// Download other attachments
					if ( !in_array( $forum_id, $this -> acl['files_download']) && in_array( $forum_id, $this -> masks[$mask_id]['files_download']))
					{
						$this -> acl['files_download'][] = $forum_id;
					}
				}
			}
		}
		
		// Return Ready ACL
		return $this -> acl;
		
	}
	
}